{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 挑选长期成长的价值股"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "import numpy as np\n",
    "import time\n",
    "\n",
    "import datetime\n",
    "\n",
    "import sys\n",
    "sys.path.append(\"../utils/\")\n",
    "import token_util\n",
    "pro = token_util.set_token()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "*获取股票列表*"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>ts_code</th>\n",
       "      <th>name</th>\n",
       "      <th>total_mv</th>\n",
       "      <th>pe_ttm</th>\n",
       "      <th>price</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>000021.SZ</td>\n",
       "      <td>深科技</td>\n",
       "      <td>2.740956e+06</td>\n",
       "      <td>77.8015</td>\n",
       "      <td>18.840</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>000025.SZ</td>\n",
       "      <td>特力A</td>\n",
       "      <td>7.504725e+05</td>\n",
       "      <td>36.2790</td>\n",
       "      <td>17.485</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>000028.SZ</td>\n",
       "      <td>国药一致</td>\n",
       "      <td>1.743333e+06</td>\n",
       "      <td>14.2903</td>\n",
       "      <td>40.705</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>000032.SZ</td>\n",
       "      <td>深桑达A</td>\n",
       "      <td>7.355310e+05</td>\n",
       "      <td>59.1230</td>\n",
       "      <td>17.985</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>000034.SZ</td>\n",
       "      <td>神州数码</td>\n",
       "      <td>1.498475e+06</td>\n",
       "      <td>21.3637</td>\n",
       "      <td>23.190</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "     ts_code  name      total_mv   pe_ttm   price\n",
       "0  000021.SZ   深科技  2.740956e+06  77.8015  18.840\n",
       "1  000025.SZ   特力A  7.504725e+05  36.2790  17.485\n",
       "2  000028.SZ  国药一致  1.743333e+06  14.2903  40.705\n",
       "3  000032.SZ  深桑达A  7.355310e+05  59.1230  17.985\n",
       "4  000034.SZ  神州数码  1.498475e+06  21.3637  23.190"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "stock_list = pd.read_csv(\"../data_pulled/stock_date_delta_price(10, 200).csv\")\n",
    "stock_list.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(549, 5)"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "stock_list.shape"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 价值股\n",
    "\n",
    "1.3年平均ROE>15%，最低的年份>10%</br>\n",
    "2.3年内现金与约当现金占资产比率最低>10%，3年平均大于15%</br>\n",
    "3.3年内净利润增长率未出现负增长，3年平均大于15%</br>\n",
    "4.3年平均流动比率>150%，3年平均速动比率>100%</br>\n",
    "5.3年平均毛利率>20%,3年平均净利率>10%</br>\n",
    "6.净利润现金含量>70%"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "*获取数据*"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 获取 roe\n",
    "def get_roe(ts_code, time_list):\n",
    "    for i in range(len(time_list)):\n",
    "                \n",
    "        ret = pro.fina_indicator(ts_code=ts_code, period='20'+str(time_list[i])+'1231', \\\n",
    "                                 fields='ts_code,end_date,roe')\n",
    "        rets = pd.concat([rets, ret], ignore_index=True) if i != 0 else ret\n",
    "    \n",
    "    return rets.drop_duplicates()[:len(time_list)].reset_index(drop=True)\n",
    "    \n",
    "\n",
    "# 获取 income 、毛利和净利润\n",
    "def get_income(ts_code, time_list):\n",
    "    for i in range(len(time_list)):\n",
    "\n",
    "        ret = pro.income(ts_code=ts_code, period='20'+str(time_list[i])+'1231', \\\n",
    "                         fields='ts_code,end_date,n_income,revenue,oper_cost')\n",
    "        rets = pd.concat([rets, ret], ignore_index=True) if i != 0 else ret\n",
    "        \n",
    "    rets['mao_li'] = (rets['revenue']-rets['oper_cost'])/rets['revenue']\n",
    "    rets['jing_li'] = rets['n_income']/rets['revenue']\n",
    "\n",
    "    return rets.drop_duplicates()[:len(time_list)].reset_index(drop=True)\n",
    "\n",
    "# 获取资产负债信息\n",
    "def get_balancesheet(ts_code, time_list):\n",
    "    for i in range(len(time_list)):\n",
    "        \n",
    "        ret = pro.balancesheet(ts_code=ts_code, period='20'+str(time_list[i])+'1231', \\\n",
    "                               fields='ts_code, end_date, inventories, total_cur_assets, \\\n",
    "                               total_cur_liab, money_cap, total_assets')\n",
    "        rets = pd.concat([rets, ret], ignore_index=True) if i != 0 else ret\n",
    "        \n",
    "    rets[\"liquidity_ratio\"] = rets[\"total_cur_assets\"]/rets[\"total_cur_liab\"] * 100\n",
    "    rets[\"quick_ratio\"] = (rets[\"total_cur_assets\"]-rets[\"inventories\"])/rets[\"total_cur_liab\"] * 100\n",
    "    rets[\"cash_ratio\"] = rets[\"money_cap\"]/rets[\"total_assets\"] * 100\n",
    "            \n",
    "    rets = rets.drop(labels=[\"inventories\",\"total_cur_assets\",\"total_cur_liab\",\"money_cap\",\"total_assets\"], axis=1)\n",
    "    \n",
    "    return rets.drop_duplicates()[:len(time_list)].reset_index(drop=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "*获取处理后的数据*"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "def get_data(stock_code, time_list):\n",
    "    data = get_roe(stock_code, time_list)\n",
    "    ret1 = get_income(stock_code, time_list)\n",
    "    ret2 = get_balancesheet(stock_code, time_list)\n",
    "\n",
    "    data[\"n_income\"] = ret1[\"n_income\"]\n",
    "    data[\"mao_li\"] = ret1[\"mao_li\"]\n",
    "    data[\"jing_li\"] = ret1[\"jing_li\"]\n",
    "    data[\"liquidity_ratio\"] = ret2[\"liquidity_ratio\"]\n",
    "    data[\"quick_ratio\"] = ret2[\"quick_ratio\"]\n",
    "    data[\"cash_ratio\"] = ret2[\"cash_ratio\"]\n",
    "    \n",
    "    return data"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "*进行筛选*"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "task accomplish: 0.18 %, cost time : 2.55 minutes\n",
      "task accomplish: 0.37 %, cost time : 5.47 minutes\n",
      "task accomplish: 0.55 %, cost time : 8.52 minutes\n",
      "task accomplish: 0.73 %, cost time : 11.3 minutes\n",
      "task accomplish: 0.91 %, cost time : 14.05 minutes\n",
      "finish task !! total time : 15.23 minutes\n"
     ]
    }
   ],
   "source": [
    "candidate_list = []\n",
    "time_list = [16, 17, 18, 19]\n",
    "times = 0\n",
    "starttime = datetime.datetime.now()\n",
    "len_stock = len(stock_list)\n",
    "\n",
    "while True:\n",
    "    \n",
    "    # 发生中断后，防止遗漏\n",
    "    start_index = 0\n",
    "    \n",
    "    for cur_index in range(start_index, len_stock):\n",
    "        \n",
    "        start_index = cur_index\n",
    "\n",
    "        try:\n",
    "            data = get_data(stock_list[\"ts_code\"][cur_index], time_list)\n",
    "        except:\n",
    "            time.sleep(5)\n",
    "        \n",
    "        times += 1\n",
    "        \n",
    "        if len(data) == 4:\n",
    "            n_income_last = np.array(data.iloc[:len(data)-1][\"n_income\"])\n",
    "            n_income_cur = np.array(data.iloc[1:][\"n_income\"])\n",
    "            net_profit_growth_rate = ((n_income_cur - n_income_last) / n_income_last) * 100\n",
    "            growth_rate_min = net_profit_growth_rate.min()\n",
    "            growth_rate_mean = net_profit_growth_rate.mean()\n",
    "\n",
    "            if data[\"roe\"][1:].min() > 10 and data[\"roe\"][1:].mean() > 15:\n",
    "                 if data[\"cash_ratio\"][1:].min() > 10 and data[\"cash_ratio\"][1:].mean() > 15:\n",
    "                    if growth_rate_min > 0 and growth_rate_mean > 15:\n",
    "                        if data[\"liquidity_ratio\"][1:].mean() > 150 and data[\"quick_ratio\"][1:].mean() > 100:\n",
    "                            candidate_list.append(stock_list[\"ts_code\"][cur_index]) \n",
    "\n",
    "        if cur_index != 0 and cur_index % 100 == 0:\n",
    "            endtime = datetime.datetime.now()\n",
    "            print(\"task accomplish: {} %, cost time : {} minutes\".format(round((cur_index+1)/len_stock, 2), \\\n",
    "                                            round((endtime - starttime).seconds / 60, 2)))\n",
    "\n",
    "    if cur_index >= len_stock - 1:\n",
    "        endtime = datetime.datetime.now()\n",
    "        print(\"finish task !! total time : {} minutes\".format(round((endtime - starttime).seconds / 60, 2)))\n",
    "        break"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "55"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "len(candidate_list)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['000568.SZ',\n",
       " '000596.SZ',\n",
       " '000858.SZ',\n",
       " '002035.SZ',\n",
       " '002127.SZ',\n",
       " '002262.SZ',\n",
       " '002271.SZ',\n",
       " '002396.SZ',\n",
       " '002402.SZ',\n",
       " '002415.SZ',\n",
       " '002439.SZ',\n",
       " '002572.SZ',\n",
       " '002677.SZ',\n",
       " '002690.SZ',\n",
       " '002737.SZ',\n",
       " '002777.SZ',\n",
       " '002821.SZ',\n",
       " '002832.SZ',\n",
       " '002867.SZ',\n",
       " '002901.SZ',\n",
       " '002912.SZ',\n",
       " '002918.SZ',\n",
       " '002947.SZ',\n",
       " '600009.SH',\n",
       " '600167.SH',\n",
       " '600197.SH',\n",
       " '600276.SH',\n",
       " '600406.SH',\n",
       " '600436.SH',\n",
       " '600486.SH',\n",
       " '600511.SH',\n",
       " '600763.SH',\n",
       " '600809.SH',\n",
       " '601100.SH',\n",
       " '601360.SH',\n",
       " '601888.SH',\n",
       " '603039.SH',\n",
       " '603060.SH',\n",
       " '603208.SH',\n",
       " '603283.SH',\n",
       " '603288.SH',\n",
       " '603338.SH',\n",
       " '603369.SH',\n",
       " '603393.SH',\n",
       " '603517.SH',\n",
       " '603568.SH',\n",
       " '603583.SH',\n",
       " '603589.SH',\n",
       " '603605.SH',\n",
       " '603659.SH',\n",
       " '603666.SH',\n",
       " '603801.SH',\n",
       " '603866.SH',\n",
       " '603882.SH',\n",
       " '603960.SH']"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "candidate_list"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>ts_code</th>\n",
       "      <th>name</th>\n",
       "      <th>total_mv</th>\n",
       "      <th>pe_ttm</th>\n",
       "      <th>price</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>548</th>\n",
       "      <td>603990.SH</td>\n",
       "      <td>麦迪科技</td>\n",
       "      <td>544168.6611</td>\n",
       "      <td>157.4574</td>\n",
       "      <td>48.6</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "       ts_code  name     total_mv    pe_ttm  price\n",
       "548  603990.SH  麦迪科技  544168.6611  157.4574   48.6"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "stock_list[(stock_list[\"ts_code\"] == stock_list[\"ts_code\"][cur_index])]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
